package org.yeasy.report.util;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ReflectUtil;
import org.yeasy.common.util.CommonBeanUtil;
import org.yeasy.report.bean.ColumnSetting;
import org.yeasy.report.constant.ColumnType;
import org.yeasy.report.constant.KeepStrategy;
import org.yeasy.report.constant.MarkConstant;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * The type Column util.列工具
 *
 * @author yangyishe
 * @date 2022年09月07日 14:52
 */
public class ColumnUtil {
    /**
     * Calc 2 field list list.计算field的list
     *
     * @param columnSettingList the report column setting list
     * @param type              the type
     * @return the list
     * @author yangyishe
     * @date 2022年09月01日 10:22
     */
    public static List<String> calc2FieldList(List<ColumnSetting> columnSettingList, Integer type) {
        return columnSettingList.stream().filter(o -> o.getType().equals(type)).map(ColumnSetting::getField).collect(Collectors.toList());
    }

    /**
     * Calc 2 field set set.计算field的set
     *
     * @param columnSettingList the report column setting list
     * @param type              the type
     * @return the set
     * @author yangyishe
     * @date 2022年09月01日 10:43
     */
    public static Set<String> calc2FieldSet(List<ColumnSetting> columnSettingList, Integer type) {
        return columnSettingList.stream().filter(o -> o.getType().equals(type)).map(ColumnSetting::getField).collect(Collectors.toSet());
    }

    /**
     * Calc 2 group key func function.
     *
     * @param <T>               the type parameter
     * @param columnSettingList the report column setting list
     * @return the function
     * @author yangyishe
     * @date 2022年09月06日 09:34
     */
    public static <T> Function<T, String> calc2GroupKeyFunc(List<ColumnSetting> columnSettingList) {
        List<String> lstGroupKeyKey = calc2FieldList(columnSettingList, ColumnType.GROUP);
        return o -> lstGroupKeyKey.stream()
                .map(s -> ReflectUtil.invoke(o, CommonBeanUtil.calcGetterName(s)).toString())
                .reduce("", (a, b) -> (a + MarkConstant.DEFAULT_UNIQUE_CHAIN_SEPARATOR + b))
                .trim();
    }

    /**
     * Clone u.
     *
     * @param <T>               the type parameter
     * @param <U>               the type parameter
     * @param source            the source
     * @param targetClazz       the target clazz
     * @param columnSettingList the column setting list
     * @return the u
     * @author yangyishe
     * @date 2022年09月14日 15:04
     */
    public static <T extends Serializable, U extends Serializable> U clone(T source, Class<U> targetClazz, List<ColumnSetting> columnSettingList) {
        U mTarget = CommonBeanUtil.newInstance(targetClazz);
        for (ColumnSetting mSetting : columnSettingList) {
            String strSourceField = mSetting.getField();
            String strTargetField = mSetting.getTargetField();
            if (CharSequenceUtil.isEmpty(strTargetField)) {
                strTargetField = strSourceField;
            }
            Object mSourceVal = CommonBeanUtil.invokeGetter(source, strSourceField);
            if (mSourceVal != null) {
                CommonBeanUtil.invokeSetter(mTarget, strTargetField, mSourceVal);
                continue;
            }
            if (mSetting.getDefaultValue() != null) {
                CommonBeanUtil.invokeSetter(mTarget, strTargetField, mSetting.getDefaultValue());
            }
        }
        return mTarget;
    }

    /**
     * Clone batch list.批量按配置克隆
     * 可用于将基础数据克隆为统计行数据
     *
     * @param <T>               the type parameter
     * @param <U>               the type parameter
     * @param sourceList        the source list
     * @param targetClazz       the target clazz
     * @param columnSettingList the column setting list
     * @return the list
     * @author yangyishe
     * @date 2022年09月14日 14:39
     */
    public static <T extends Serializable, U extends Serializable> List<U> cloneBatch(List<T> sourceList,
                                                                                      Class<U> targetClazz,
                                                                                      List<ColumnSetting> columnSettingList) {
        List<U> lstTarget = new ArrayList<>();
        for (T mSource : sourceList) {
            lstTarget.add(clone(mSource, targetClazz, columnSettingList));
        }
        return lstTarget;
    }

    /**
     * Merge obj.
     *
     * @param <T>               the type parameter
     * @param <U>               the type parameter
     * @param mergeObj          the merge obj
     * @param prevObj           the prev obj
     * @param nextObj           the next obj
     * @param columnSettingList the column setting list
     * @author yangyishe
     * @date 2022年09月13日 09:36
     */
    public static <T extends Serializable, U> void mergeObj(T mergeObj, T prevObj, T nextObj, List<ColumnSetting> columnSettingList) {
        List<ColumnSetting> lstKeepSetting = columnSettingList.stream().filter(o -> o.getType().equals(ColumnType.KEEP)).collect(Collectors.toList());
        for (ColumnSetting<U> mSetting : lstKeepSetting) {
            String strField = mSetting.getField();
            Integer intStrategy = mSetting.getKeepStrategy();
            U preVal = CommonBeanUtil.invokeGetter(prevObj, strField);
            U nextVal = CommonBeanUtil.invokeGetter(nextObj, strField);
            U mergeVal = KeepStrategy.getInstance(intStrategy, mSetting.getDefaultValue()).mergeValue(preVal, nextVal);
            CommonBeanUtil.invokeSetter(mergeObj, strField, mergeVal);
        }
    }
}
